<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>葡萄藤PPT</title>

    <link rel="stylesheet" href="../css/reveal/reveal.css">

    <!-- PPT主题，可以在/css/reveal/theme/中选择其他主题，目前暂时只能使用该模板 -->
    <link rel="stylesheet" href="../css/reveal/theme/ptt.css">

    <!-- syntax highlighting 代码高亮主题 -->
    <link rel="stylesheet" href="../lib/reveal/css/zenburn.css">

    <!-- 打印和PDF输出样式 -->
    <script>
        var link = document.createElement( 'link' );
        link.rel = 'stylesheet';
        link.type = 'text/css';
        link.href = window.location.search.match( /print-pdf/gi ) ? '../css/reveal/print/pdf.css' : '../css/reveal/print/paper.css';
        document.getElementsByTagName( 'head' )[0].appendChild( link );
    </script>
</head>
<body>
<img src="../img/demo/logo.png" alt="" usemap="#pttmap" class="base-logo">
<map name="pttmap">
    <area shape="rect" coords="0,0,276,58" href="http://www.jnshu.com" alt="" target="_blank"/>
</map>
<div class="reveal">
    <div class="slides">
        <section>
            <h2>js中的callback</h2>

            <p>分享人：文世豪</p>
        </section>
        <section>
            <p>目录</p>
            <p>1.背景介绍</p>
            <p>2.知识剖析</p>
            <p>3.常见问题</p>
            <p>4.解决方案</p>
            <p>5.编码实战</p>
            <p>6.扩展思考</p>
            <p>7.参考文献</p>
            <p>8.更多讨论</p>
        </section>
        <section>
            <h3>1.背景介绍</h3>
        </section>
        <section>
            <p>在我们接触ajax，与angularjs中的数据请求时，我们总是听到里面的回调函数，callback。我们在使用的过程中总感觉它是一个混淆的概念，它仿佛是ajax请求后调用的那个函数，又感觉它是某一个函数的形参而已。在后面angular和promise的学习中，我们会遇到非常多的回调函数，因此我们有必要弄清其中的概念</p>
        </section>
        <section>
            <h3>2.知识剖析</h3>
        </section>
        <section>
            <p>
                我们都知道js是单线程的，这种设计模式给我们带来了很多的方便之处，我们不需要考虑各个线程之间的通信，也不需要写很多烧脑的代码，也就是说js的引擎只能一件一件事的去完成和执行相关的操作，所以所有需要执行的事情都像排队一样，等待着被触发和执行，可是如果这样的话，如果在队列中有一件事情需要花费很多的时间，那么后面的任务都将处于一种等待状态，有时甚至会出现浏览器假死现象，例如其中有一件正在执行的一个任务是一个死循环，那么会导致后续其他的任务无法正常执行，所以js在同步机制的缺陷下设计出了异步模式
                在异步执行的模式下，每一个异步的任务都有其自己一个或着多个回调函数，这样当前在执行的异步任务执行完之后，不会马上执行事件队列中的下一项任务，而是执行它的回调函数，而下一项任务也不会等当前这个回调函数执行完，因为它也不能确定当前的回调合适执行完毕，只要引它被触发就会执行
            </p>
        </section>
            <section>
                <p>
                 1.搞清楚异步和同步</p>
                 <p>1.早上起来不论你是先刷牙还是先洗脸，都要等一个事情完毕后才能进行下一项，这就是一个同步的例子
                     2.然后刷牙的时候你也可以烧水喝 （不用等你刷完牙）这就是一个异步的例子
                </p>
                <code>
                    <pre>
 function a(){
        console.log("执行函数a");
        setTimeout(function(){
            console.log('执行a的延迟函数')
        },1000)
    }
    function b(){
        console.log('执行函数b')
    }
    a();
    b();
                    </pre>
                </code>
            </section>
        <section>
            <p>
                调用 setTimeout 函数会在一个时间段过去后在队列中添加一个消息。这个时间段作为函数的第二个参数被传入。如果队列中没有其它消息，消息会被马上处理。但是，如果有其它消息，setTimeout 消息必须等待其它消息处理完。因此第二个参数仅仅表示最少的时间 而非确切的时间
            </p>
            <code><pre>
                var a=0;
    function change() {
        a=1;
    }
    function after(){
        console.log(a);
    }
    change();
    after();
            </pre></code>
        </section>
            <section>
            <p>
               2.回调函数到底是什么？<br/>
                <strong>A callback is a function that is passed as an argument to another function and is executed after its parent function has completed.</strong>
            </p>
        </section>
        <section>
               <p>3.回调函数是怎么运作的</p>
               <p>因为函数在Javascript中是第一类对象，我们像对待对象一样对待函数，因此我们能像传递变量一样传递函数，在函数中返回函数，在其他函数中使用函数。当我们将一个回调函数作为参数传递给另一个函数是，我们仅仅传递了函数定义。我们并没有在参数中执行函数。我们并不传递像我们平时执行函数一样带有一对执行小括号()的函数。</p>
        </section>
        <section>
            <p>
                人话：字面上理解下来就是，回调就是一个函数的调用过程。那么就从理解这个调用过程开始吧。函数a有一个参数，这个参数是个函数b，当函数a执行完以后执行函数b。那么这个过程就叫回调。
            </p>
            <p>这里必须清楚一点：函数b是你以参数形式传给函数a的，那么函数b就叫回调函数。</p>

        </section>
         <section>  
            <h3>3.常见问题</h3>
        </section>
        <section>
            <p>1.为什么写回调函数</p>
            <p>2.回调函数一定要以参数形式传过去吗，我不可以直接在函数a里面调用函数b吗？</p>
        </section>

        <section>
            <h3>4.解决方案</h3>
        </section>
        <section>
            <code>
                <pre>
                    function a(callback)
    {
        console.log("我是parent函数a！");
        console.log("调用回调函数");
        callback();
    }
    function b(){
        console.log("我是回调函数b");

    }
    function c(){
        console.log("我是回调函数c");

    }

    function test()
    {
        a(b);
        a(c);
    }
    test();
                </pre>
            </code>

        </section>
        <section>
            <p>如果你直接在函数a里调用的话，那么这个回调函数就被限制死了。但是使用函数做参数就有下面的好处：当你a(b)的时候函数b就成了回调函数，而你还可以a(c)这个时候，函数c就成了回调函数。如果你写成了function a(){...;b();}就失去了变量的灵活性。</p>
            <p>启示：函数在javascript中和数据一样，可以赋值，删除，拷贝，自然也可以作为函数的参数</p>
        </section>
        <section>
            <h3>5.编码实战</h3>
        </section>
        <section>
            <h3>6.扩展思考</h3>
        </section>
        <section>
           <p>回调函数与ES6中的promise</p>
        </section>
        <section>
            <h3>7.参考文献</h3>
        </section>

        <section>
            <h4>鸣谢</h4>
            <p>感谢大家观看</p>
            <p><small>BY : 文世豪</small></p>
        </section>
    </div>
</div>

<script src="../lib/reveal/js/head.min.js"></script>
<script src="../lib/reveal/reveal.js"></script>

<script>

    // 以下为常见配置属性的默认值
    // {
    // 	controls: true, // 是否在右下角展示控制条
    // 	progress: true, // 是否显示演示的进度条
    // 	slideNumber: false, // 是否显示当前幻灯片的页数编号，也可以使用代码slideNumber: 'c / t' ，表示当前页/总页数。
    // 	history: false, // 是否将每个幻灯片改变加入到浏览器的历史记录中去
    // 	keyboard: true, // 是否启用键盘快捷键来导航
    // 	overview: true, // 是否启用幻灯片的概览模式，可使用"Esc"或"o"键来切换概览模式
    // 	center: true, // 是否将幻灯片垂直居中
    // 	touch: true, // 是否在触屏设备上启用触摸滑动切换
    // 	loop: false, // 是否循环演示
    // 	rtl: false, // 是否将演示的方向变成RTL，即从右往左
    // 	fragments: true, // 全局开启和关闭碎片。
    // 	autoSlide: 0, // 两个幻灯片之间自动切换的时间间隔（毫秒），当设置成 0 的时候则禁止自动切换，该值可以被幻灯片上的 ` data-autoslide` 属性覆盖
    // 	transition: 'default', // 切换过渡效果，有none/fade/slide/convex/concave/zoom
    // 	transitionSpeed: 'default', // 过渡速度，default/fast/slow
    // 	mouseWheel: true, //是否启用通过鼠标滚轮来切换幻灯片
    // }

    // 初始化幻灯片
    Reveal.initialize({
        history: true,
        dependencies: [
            { src: '../plugin/markdown/marked.js' },
            { src: '../plugin/markdown/markdown.js' },
            { src: '../plugin/notes/notes.js', async: true },
            { src: '../plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }
        ]
    });
</script>
<script>
    //过滤掉小于 10 的数组元素：

    //代码：
    document.getElementById("a").onclick = isBigEnough();
    function isBigEnough(element, index, array) {
        return (element >= 10);
    }
    var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
    // 12, 130, 44
    //结果：[12, 5, 8, 130, 44].filter(isBigEnough) ： 12, 130, 44
    console.log(filtered);
    ///11111111111
    //检查是否有数组元素大于等于10：
    document.getElementById("b").onclick = isBigEnoug();
    function isBigEnoug(element, index, array) {
        return (element >= 10);
    }
    var passed = [2, 5, 8, 1, 4].some(isBigEnoug);
    // passed is false
    passed2 = [12, 5, 8, 1, 4].some(isBigEnoug);
    // passed is true
    //结果：
    //[2, 5, 8, 1, 4].some(isBigEnough) ： false
    //[12, 5, 8, 1, 4].some(isBigEnough) ： true
    console.log(passed);
    console.log(passed2);
    ////2222222222222222222222
    //将所有的数组元素转换为大写：
    document.getElementById("c").onclick = makeUpperCase();
    var strings = ["hello", "Array", "WORLD"];
    function makeUpperCase(v)
    {
        return v.toUpperCase();
    }
    var uppers = strings.map(makeUpperCase);
    // uppers is now ["HELLO", "ARRAY", "WORLD"]
    // strings is unchanged
    //结果：["hello", "Array", "WORLD"].map(makeUpperCase) ： HELLO, ARRAY, WORLD
    console.log(uppers);
    /////333333333333333333
    document.getElementById("d").onclick = printElt();
    //打印数组内容：

    function printElt(element, index, array) {
        document.writeln("[" + index + "] is " + element + "<br />");
    }
    [2, 5, 9].forEach(printElt);
    // Prints:
    // [0] is 2
    // [1] is 5
    // [2] is 9
    //结果：
    //[0] is 2
    //[1] is 5
    //[2] is 9
    /////////44444444444444
</script>
</body>
</html>
